package com.sbwebsocket.core.redis.config;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sbwebsocket.core.config.WsAppConfig;
import com.sbwebsocket.core.redis.*;
import com.sbwebsocket.core.redis.model.contants.WsMessageRedisKeyPrefix;
import com.sbwebsocket.core.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Auther: GSJ
 * @Date: 2022/2/10
 * @Description:
 * @version: 1.0
 */
public class RedisConfig extends AbstractMessageQueueAdapter {

    @Bean
    public RedisDirectMessageQueue directRedisMessageQueue() {
        return new RedisDirectMessageQueue();
    }

    @Bean
    public RedisFanoutMessageQueue fanoutRedisMessageQueue() {
        return new RedisFanoutMessageQueue();
    }

    @Bean
    public RedisTopicMessageQueue topicRedisMessageQueue() {
        return new RedisTopicMessageQueue();
    }

    @Autowired
    WsAppConfig appConfig;

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(factory);
        //key序列化
        RedisSerializer keySerializer = new StringRedisSerializer();
        RedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setKeySerializer(keySerializer);
        //value序列化
        redisTemplate.setValueSerializer(valueSerializer);
        //hash key 序列化
        redisTemplate.setHashKeySerializer(keySerializer);
        //hash value 序列化
        redisTemplate.setHashValueSerializer(valueSerializer);
        //redis初始化
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplateGroup(RedisConnectionFactory factory) {
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(factory);
        RedisSerializer keySerializer = new StringRedisSerializer();
        RedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(getMapper());
        redisTemplate.setKeySerializer(keySerializer);
        redisTemplate.setValueSerializer(valueSerializer);
        redisTemplate.setHashKeySerializer(keySerializer);
        redisTemplate.setHashValueSerializer(valueSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                   MessageListenerAdapter directListenerAdapter,
                                                   MessageListenerAdapter fanoutListenerAdapter,
                                                   MessageListenerAdapter topicListenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //接受消息的key
        container.addMessageListener(directListenerAdapter,
                new PatternTopic(WsMessageRedisKeyPrefix.SERVER_MSG_DIRECT + appConfig.getHostKey()));
        container.addMessageListener(fanoutListenerAdapter,
                new PatternTopic(WsMessageRedisKeyPrefix.SERVER_MSG_FANOUT));

        container.addMessageListener(topicListenerAdapter,
                new PatternTopic(WsMessageRedisKeyPrefix.SERVER_MSG_TOPIC_QUEUE));

        return container;
    }

    /**
     * 直连消息接收
     *
     * @param
     * @return
     */
    @Bean
    public MessageListenerAdapter directListenerAdapter(RedisDirectMessageReceiver directReceiver) {
        return new MessageListenerAdapter(directReceiver, "receive");
    }

    @Bean
    RedisDirectMessageReceiver directReceiver() {
        return new RedisDirectMessageReceiver();
    }

    /**
     * 广播消息接收
     *
     * @param
     * @return
     */
    @Bean
    public MessageListenerAdapter fanoutListenerAdapter(RedisFanoutMessageReceiver fanoutReceiver) {
        return new MessageListenerAdapter(fanoutReceiver, "receive");
    }

    @Bean
    public MessageListenerAdapter topicListenerAdapter(RedisTopicMessageReceiver topicReceiver) {
        return new MessageListenerAdapter(topicReceiver, "receive");
    }

    @Bean
    RedisFanoutMessageReceiver fanoutReceiver() {
        return new RedisFanoutMessageReceiver();
    }

    @Bean
    RedisTopicMessageReceiver topicReceiver() {
        return new RedisTopicMessageReceiver();
    }


    @Bean
    UnusualMessageManager redisUnusualMessageManager() {
        return new RedisDelayProcUnusualMessage();
    }


    @Bean
    OfflineMessageManager redisOfflineMessageManager() {
        return new RedisOfflineMessageManager();
    }

    @Bean
    MessageDeliveryListener messageDeliveryListener(UnusualMessageManager redisUnusualMessageManager,
                                                    OfflineMessageManager redisOfflineMessageManager) {
        return new DefaultMessageDeliveryListener(redisUnusualMessageManager, redisOfflineMessageManager);
    }

    @Bean
    TopicMessageManager topicMessageManager(){
        return new RedisTopicMessageManager();
    }
    
    
    /**
     * 获取JSON工具
     *
     * @return
     */
    private final ObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        //将类名称序列化到json串中，去掉会导致得出来的的是LinkedHashMap对象，直接转换实体对象会失败
        //设置输入时忽略JSON字符串中存在而Java对象实际没有的属性
        //其中该配置，需要升级fasterxml版本
        //mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }
    
    @Bean
    CycleProcessUnusualOfflineClientMessage cycleProcessUnusualOfflineClientMessage(){
        return new CycleProcessUnusualOfflineClientMessage();
    }

}
